package gui.environmentEditor;

import gui.WuselPanelInterface;
import importExport.EnvironmentImportExport;
import importExport.log.WuselLogger;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Properties;

import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.ListSelectionModel;
import javax.swing.SwingConstants;
import javax.swing.SwingWorker;

import language.LanguageProfiler;
import dataTypes.Environment;
import dataTypes.environment.IntersectionPoint;

/**
 * @author Kevin Wagner
 * @version 1.0
 */
public class EnvironmentEditorPanel extends JPanel implements
		WuselPanelInterface, ActionListener, MouseListener, MouseMotionListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 7131463686212823127L;
	private LanguageProfiler lp;
	private Properties props;
	private long id = 0;

	private DefaultListModel lm = new DefaultListModel();
	private JList list = new JList(lm);

	private JLabel environmentL, nameL, populationL, mouseModeL;
	private JButton newBtn, deleteBtn, saveBtn;
	private JTextField nameTxt, populationTxt;

	private JRadioButton addRB, moveRB, deleteRB;

	private JPanel paintPanel = new JPanel();
	private JFrame paintFrame = new JFrame();

	private ArrayList<Environment> envs = new ArrayList<Environment>();
	private Environment selectedEnv;
	private IntersectionPoint selectedIntPoint;
	private boolean intersecChange = false;

	/**
	 * Create the panel.
	 * 
	 * @param props
	 * @param lp
	 */
	public EnvironmentEditorPanel(Properties props, LanguageProfiler lp) {
		this.lp = lp;
		this.props = props;

		environmentL = new JLabel();

		list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		list.addListSelectionListener(new ListSelectionListener() {

			@Override
			public void valueChanged(ListSelectionEvent e) {
				if (list.getSelectedIndex() > -1) {
					selectedEnv = envs.get(list.getSelectedIndex());
					if (selectedEnv != null) {
						fillFields();
					}
				}
			}
		});

		newBtn = new JButton();
		newBtn.addActionListener(this);

		deleteBtn = new JButton();
		deleteBtn.addActionListener(this);

		JSeparator separator = new JSeparator();
		separator.setOrientation(SwingConstants.VERTICAL);

		nameL = new JLabel();

		nameTxt = new JTextField();
		nameTxt.setColumns(30);

		populationL = new JLabel();

		populationTxt = new JTextField();
		populationTxt.setColumns(10);

		saveBtn = new JButton();
		saveBtn.addActionListener(this);

		mouseModeL = new JLabel();

		Box verticalBox = Box.createVerticalBox();

		GroupLayout groupLayout = new GroupLayout(this);
		groupLayout
				.setHorizontalGroup(groupLayout
						.createParallelGroup(Alignment.LEADING)
						.addGroup(
								groupLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												groupLayout
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																list,
																GroupLayout.PREFERRED_SIZE,
																200,
																GroupLayout.PREFERRED_SIZE)
														.addComponent(
																deleteBtn,
																GroupLayout.DEFAULT_SIZE,
																200,
																Short.MAX_VALUE)
														.addComponent(
																newBtn,
																GroupLayout.DEFAULT_SIZE,
																200,
																Short.MAX_VALUE)
														.addComponent(
																environmentL,
																GroupLayout.DEFAULT_SIZE,
																200,
																Short.MAX_VALUE))
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addComponent(separator,
												GroupLayout.PREFERRED_SIZE, 4,
												GroupLayout.PREFERRED_SIZE)
										.addPreferredGap(
												ComponentPlacement.RELATED)
										.addGroup(
												groupLayout
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(saveBtn)
														.addComponent(
																mouseModeL)
														.addGroup(
																groupLayout
																		.createSequentialGroup()
																		.addGroup(
																				groupLayout
																						.createParallelGroup(
																								Alignment.TRAILING)
																						.addComponent(
																								verticalBox,
																								Alignment.LEADING,
																								GroupLayout.DEFAULT_SIZE,
																								325,
																								Short.MAX_VALUE)
																						.addGroup(
																								Alignment.LEADING,
																								groupLayout
																										.createSequentialGroup()
																										.addComponent(
																												nameL)
																										.addPreferredGap(
																												ComponentPlacement.RELATED)
																										.addComponent(
																												nameTxt,
																												GroupLayout.DEFAULT_SIZE,
																												266,
																												Short.MAX_VALUE)))
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				populationL)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				populationTxt,
																				GroupLayout.DEFAULT_SIZE,
																				357,
																				Short.MAX_VALUE)))
										.addContainerGap()));
		groupLayout
				.setVerticalGroup(groupLayout
						.createParallelGroup(Alignment.TRAILING)
						.addGroup(
								groupLayout
										.createSequentialGroup()
										.addContainerGap()
										.addGroup(
												groupLayout
														.createParallelGroup(
																Alignment.LEADING)
														.addComponent(
																separator,
																GroupLayout.DEFAULT_SIZE,
																502,
																Short.MAX_VALUE)
														.addGroup(
																groupLayout
																		.createSequentialGroup()
																		.addGroup(
																				groupLayout
																						.createParallelGroup(
																								Alignment.BASELINE)
																						.addComponent(
																								nameL)
																						.addComponent(
																								nameTxt,
																								GroupLayout.PREFERRED_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.PREFERRED_SIZE)
																						.addComponent(
																								populationTxt,
																								GroupLayout.PREFERRED_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.PREFERRED_SIZE)
																						.addComponent(
																								populationL))
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				mouseModeL)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				verticalBox,
																				GroupLayout.PREFERRED_SIZE,
																				GroupLayout.DEFAULT_SIZE,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED,
																				364,
																				Short.MAX_VALUE)
																		.addComponent(
																				saveBtn))
														.addGroup(
																groupLayout
																		.createSequentialGroup()
																		.addComponent(
																				environmentL,
																				GroupLayout.PREFERRED_SIZE,
																				24,
																				GroupLayout.PREFERRED_SIZE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				list,
																				GroupLayout.DEFAULT_SIZE,
																				414,
																				Short.MAX_VALUE)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				newBtn)
																		.addPreferredGap(
																				ComponentPlacement.RELATED)
																		.addComponent(
																				deleteBtn)))
										.addContainerGap()));

		addRB = new JRadioButton();
		addRB.setSelected(true);
		verticalBox.add(addRB);

		moveRB = new JRadioButton();
		verticalBox.add(moveRB);

		deleteRB = new JRadioButton();
		verticalBox.add(deleteRB);

		ButtonGroup group = new ButtonGroup();
		group.add(addRB);
		group.add(moveRB);
		group.add(deleteRB);

		setLayout(groupLayout);
		updateLanguage();
		loadData();
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		int width = (int) Math.round(screenSize.getWidth());
		int height = (int) Math.round(screenSize.getHeight());
		if (width < 1080 && height < 1080) {
			paintPanel.setPreferredSize(new Dimension(500, 500));
			paintPanel.setMinimumSize(new Dimension(500, 500));
			paintPanel.setMaximumSize(new Dimension(500, 500));
		} else {
			paintPanel.setPreferredSize(new Dimension(1000, 1000));
			paintPanel.setMinimumSize(new Dimension(1000, 1000));
			paintPanel.setMaximumSize(new Dimension(1000, 1000));
		}
		paintPanel.addMouseListener(this);
		paintPanel.addMouseMotionListener(this);
		paintPanel.setDoubleBuffered(true);
		paintFrame.setResizable(false);
		paintFrame.addComponentListener(new ComponentListener() {

			@Override
			public void componentShown(ComponentEvent e) {
			}

			@Override
			public void componentResized(ComponentEvent e) {
			}

			@Override
			public void componentMoved(ComponentEvent e) {
				if (selectedEnv != null) {
					paintEnv();
				}
			}

			@Override
			public void componentHidden(ComponentEvent e) {
			}
		});
		paintFrame.getContentPane().add(paintPanel);
		paintFrame.pack();
		paintFrame.setVisible(true);
		paintFrame.setLocation(width - paintFrame.getWidth(), 0);
		fillFields();
	}

	private void loadData() {
		envs = EnvironmentImportExport.importEnvironment(props);
		fillList();
		if (envs.size() > 0) {
			selectedEnv = envs.get(0);
			list.setSelectedIndex(0);
			id = selectedEnv.getMaxID() + 1;
		}

	}

	private void fillFields() {
		nameTxt.setText(selectedEnv.getName());
		populationTxt.setText(selectedEnv.getPopulation() + "");
		new SwingWorker<Object, Object>() {

			@Override
			protected Object doInBackground() throws Exception {
				Thread.sleep(100);
				if (selectedEnv != null) {
					paintEnv();
				}
				return null;
			}
		}.execute();
	}

	private void fillList() {
		lm.removeAllElements();
		for (int i = 0; i < envs.size(); i++) {
			lm.addElement(envs.get(i).getName());
		}
	}

	@Override
	public boolean checkForChanges() {
		if (selectedEnv == null) {
			return false;
		}
		if (!selectedEnv.getName().equals(nameTxt.getText())) {
			return true;
		}
		if (selectedEnv.getPopulation() != Integer.parseInt(populationTxt
				.getText())) {
			return true;
		}
		return intersecChange;
	}

	@Override
	public boolean saveData() {
		try {
			selectedEnv.setName(nameTxt.getText());
			int pop = Integer.parseInt(populationTxt.getText());
			selectedEnv.setPopulation(pop);
			EnvironmentImportExport.exportEnvironment(selectedEnv, new File(
					props.getProperty("environmentDir", "Environment")));
		} catch (Exception e) {
			WuselLogger.log.error(e.getLocalizedMessage());
			JOptionPane.showMessageDialog(
					this,
					lp.getLocalizedString("saveError") + " \n"
							+ e.getLocalizedMessage(),
					lp.getLocalizedString("saveErrorTitle"),
					JOptionPane.ERROR_MESSAGE);
			return false;
		}
		return true;
	}

	@Override
	public void updateLanguage() {
		environmentL.setText(lp.getLocalizedString("environments"));
		nameL.setText(lp.getLocalizedString("name"));
		populationL.setText(lp.getLocalizedString("population"));
		mouseModeL.setText(lp.getLocalizedString("mouseMode"));

		addRB.setText(lp.getLocalizedString("addPoint"));
		moveRB.setText(lp.getLocalizedString("movePoint"));
		deleteRB.setText(lp.getLocalizedString("deletePoint"));

		deleteBtn.setText(lp.getLocalizedString("delete"));
		newBtn.setText(lp.getLocalizedString("new"));
		saveBtn.setText(lp.getLocalizedString("save"));

	}

	@Override
	public boolean confirmDialog() {
		int result = JOptionPane.showConfirmDialog(this,
				lp.getLocalizedString("confirmChanges"),
				lp.getLocalizedString("confirmChangesTitle"),
				JOptionPane.YES_NO_OPTION);
		if (result == JOptionPane.YES_OPTION) {
			return saveData();
		}
		return true;
	}

	private int getSelectionMode() {
		// 0:add point
		// 1:edit point
		// 2:delete point
		if (addRB.isSelected()) {
			return 0;
		} else if (moveRB.isSelected()) {
			return 1;
		} else if (deleteRB.isSelected()) {
			return 2;
		}
		return 0;
	}

	private void paintEnv() {
		int factor = 1;
		if (paintPanel.getWidth() == 500) {
			factor = 2;
		}
		Graphics g = paintPanel.getGraphics();
		g.setColor(Color.white);
		g.fillRect(0, 0, paintPanel.getWidth(), paintPanel.getHeight());
		g.setColor(Color.red);
		for (int i = 0; i < selectedEnv.getIntersectionPoints().size(); i++) {
			IntersectionPoint intersec = selectedEnv.getIntersectionPoints()
					.get(i);
			int x = intersec.getX();
			int y = intersec.getY();
			g.fillOval((x / factor) - 4, (y / factor) - 4, 9, 9);
		}
	}

	private IntersectionPoint getSelectedIntersectionPoint(int x, int y) {
		for (int i = 0; i < selectedEnv.getIntersectionPoints().size(); i++) {
			IntersectionPoint p = selectedEnv.getIntersectionPoints().get(i);
			if (x > p.getX() - 5 && x < p.getX() + 5) {
				if (y > p.getY() - 5 && y < p.getY() + 5) {
					return p;
				}
			}
		}
		return null;
	}

	// ///////////////////////////////////////////////////////////////////////////////////////
	// /////////////////////////////Action
	// Listener////////////////////////////////////////////
	// ///////////////////////////////////////////////////////////////////////////////////////
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getSource() == newBtn) {
			boolean status = true;
			if (checkForChanges()) {
				status = confirmDialog();
			}
			if (status) {
				Environment env = new Environment();
				env.setName("Name");
				envs.add(env);
				fillList();
				selectedEnv = env;
				fillFields();
			}
		} else if (e.getSource() == deleteBtn) {
			boolean status = true;
			if (envs.get(list.getSelectedIndex()) != selectedEnv) {
				if (checkForChanges()) {
					status = status && confirmDialog();
				}
			}
			if (status) {
				if (EnvironmentImportExport.deleteEnvironmentFile(
						envs.get(list.getSelectedIndex()), props)) {
					envs.remove(list.getSelectedIndex());
					fillList();
					if (envs.size() > 0) {
						list.setSelectedIndex(0);
						fillFields();
						selectedEnv = envs.get(0);
					}
					JOptionPane.showMessageDialog(this,
							lp.getLocalizedString("entryDelete"),
							lp.getLocalizedString("entryDelete"),
							JOptionPane.INFORMATION_MESSAGE);
				} else {
					JOptionPane.showMessageDialog(this,
							lp.getLocalizedString("deleteError"),
							lp.getLocalizedString("deleteErrorTitle"),
							JOptionPane.ERROR_MESSAGE);
				}
			}
		} else if (e.getSource() == saveBtn) {
			saveData();
			fillList();
		}

	}

	// ///////////////////////////////////////////////////////////////////////////////////////
	// /////////////////////////////Mouse
	// Listener////////////////////////////////////////////
	// ///////////////////////////////////////////////////////////////////////////////////////
	@Override
	public void mouseClicked(MouseEvent e) {
	}

	@Override
	public void mouseEntered(MouseEvent e) {
	}

	@Override
	public void mouseExited(MouseEvent e) {
	}

	@Override
	public void mousePressed(MouseEvent e) {
		int mode = getSelectionMode();
		if (mode == 0) {
			selectedEnv.addIntersectionPoint(id, e.getX(), e.getY());
			id++;
			intersecChange = true;
			paintEnv();
		} else if (mode == 1) {
			selectedIntPoint = getSelectedIntersectionPoint(e.getX(), e.getY());
		} else if (mode == 2) {
			selectedIntPoint = getSelectedIntersectionPoint(e.getX(), e.getY());
			if (selectedIntPoint != null) {
				selectedEnv.getIntersectionPoints().remove(selectedIntPoint);
				selectedIntPoint = null;
				intersecChange = true;
				paintEnv();
			}
		}

	}

	@Override
	public void mouseReleased(MouseEvent e) {
		if (getSelectionMode() == 1 && selectedIntPoint != null) {
			selectedIntPoint.setX(e.getX());
			selectedIntPoint.setY(e.getY());
			selectedIntPoint = null;
			intersecChange = true;
			paintEnv();
		}

	}

	// ///////////////////////////////////////////////////////////////////////////////////////
	// //////////////////////////Mouse Motion
	// Listener////////////////////////////////////////
	// ///////////////////////////////////////////////////////////////////////////////////////
	@Override
	public void mouseDragged(MouseEvent e) {
		if (getSelectionMode() == 1 && selectedIntPoint != null) {
			selectedIntPoint.setX(e.getX());
			selectedIntPoint.setY(e.getY());
			intersecChange = true;
			paintEnv();
		}
	}

	@Override
	public void mouseMoved(MouseEvent e) {
	}
}
